#include "mcu_can.h"
#include "polsys.h"

// 预处理

#define F_PCLK1_MHZ (F_PCLK1/1000000)

#if (F_PCLK1_MHZ % 18 == 0)  // 能被18整除
    #define CAN_TBS1    CAN_TBS1_14tq    /*14 + 4 = 18*/ 
    #define CAN_BIT_CYCLE   18  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 17 == 0) 
    #define CAN_TBS1    CAN_TBS1_13tq    /*13 + 4 = 17*/ 
    #define CAN_BIT_CYCLE   17  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 16 == 0) 
    #define CAN_TBS1    CAN_TBS1_12tq    /*12 + 4 = 16*/ 
    #define CAN_BIT_CYCLE   16  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 15 == 0) 
    #define CAN_TBS1    CAN_TBS1_11tq    /*11 + 4 = 15*/ 
    #define CAN_BIT_CYCLE   15  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 14 == 0) 
    #define CAN_TBS1    CAN_TBS1_10tq    /*10 + 4 = 14*/ 
    #define CAN_BIT_CYCLE   14  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 13 == 0) 
    #define CAN_TBS1    CAN_TBS1_9tq    /*9 + 4 = 13*/ 
    #define CAN_BIT_CYCLE   13  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 12 == 0) 
    #define CAN_TBS1    CAN_TBS1_8tq    /*8 + 4 = 12*/ 
    #define CAN_BIT_CYCLE   12  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 11 == 0) 
    #define CAN_TBS1    CAN_TBS1_7tq    /*7 + 4 = 11*/ 
    #define CAN_BIT_CYCLE   11  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 10 == 0) 
    #define CAN_TBS1    CAN_TBS1_6tq    /*6 + 4 = 10*/ 
    #define CAN_BIT_CYCLE   10  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 9 == 0) 
    #define CAN_TBS1    CAN_TBS1_5tq    /*5 + 4 = 9*/ 
    #define CAN_BIT_CYCLE   9  /* 一个位占用的时钟数 */
#elif (F_PCLK1_MHZ % 8 == 0)
    #define CAN_TBS1    CAN_TBS1_4tq    /*4 + 4 = 8*/ 
    #define CAN_BIT_CYCLE   8  /* 一个位占用的时钟数 */
#else
    #error "Common CAN rates cannot be set for PCLK1 frequencies."
#endif

#define  CAN_FILTER_STDID(STDID)        ((STDID&0x7FF)<<5)
#define  CAN_FILTER_EXTID_H(EXTID)      ((uint16_t)(((EXTID>>18)<<5)|((EXTID&0x2FFFF)>>13)))
#define  CAN_FILTER_EXTID_L(EXTID)      ((uint16_t)((EXTID&0x2FFFF)<<3))

struct _can_t
{
    CAN_Module *CANInstance;    // 寄存器实例

    can_rx_cb_t *RxCb;
    void **RxCbParam;
    u8 RxCbMaxNum;
    u8 RxCbNum;

    bool Sending;   // true: 正在发送（发送缓存中有数据）
    bool IsOpen;    // true: 开启
    polsys_task_t NotifyTask;
    can_msg_t NotifyingMsg; // 正在通知（处理）的消息
};

// 静态变量定义


// 因为MCU的硬件CAN接口是固定数量的，实例化更多的 can_t 对象没意义，所以在这里统一实例化全部对象。

#ifdef _CAN_USE_CAN1
static can_rx_cb_t Can1RxCBList[_CAN_CAN1_RX_CB_NUM];
static void *Can1RxCbParamList[_CAN_CAN1_RX_CB_NUM];
can_t _CAN_CAN1_NAME = {
    .CANInstance = CAN1,
    .RxCb = Can1RxCBList,
    .RxCbParam = Can1RxCbParamList,
    .RxCbMaxNum = _CAN_CAN1_RX_CB_NUM,
    .RxCbNum = 0,
    .Sending = false,
    .IsOpen = false
    };
#endif

#ifdef _CAN_USE_CAN2
static can_rx_cb_t Can2RxCBList[_CAN_CAN2_RX_CB_NUM];
static void *Can2RxCbParamList[_CAN_CAN2_RX_CB_NUM];
can_t _CAN_CAN2_NAME = {
    .CANInstance = CAN2,
    .RxCb = Can2RxCBList,
    .RxCbParam = Can2RxCbParamList,
    .RxCbMaxNum = _CAN_CAN2_RX_CB_NUM,
    .RxCbNum = 0,
    .Sending = false,
    .IsOpen = false
    };
#endif

// 内部函数申明

static void NotifyMsg(can_t *this, CanRxMessage *lrmsg);
static void NotifyTaskEntry(can_t *this);
static void CAN_InitFilter(CAN_Module *CANx, CAN_FilterInitType* CAN_InitFilterStruct);
static void CAN_ConfigINT(CAN_Module* CANx, uint32_t CAN_INT, FunctionalState Cmd);


// 中断入口

/**
 * CAN中断统一入口。此函数未进行中断标记清除操作。
 * @param this CAN接口对象
 * @param int_flag 中断标记（发生了什么中断），使用库函数中定义好的标记。
*/
void Can_IRQHandler(can_t *this, u32 int_flag)
{
    CanRxMessage lib_rx_msg;
    switch(int_flag)
    {
    case CAN_INT_FMP0:  // FIFO0 有消息等待读出（收到了数据）
        CAN_ReceiveMessage(this->CANInstance, CAN_FIFO0, &lib_rx_msg);
        NotifyMsg(this, &lib_rx_msg);
        break;
    case CAN_INT_FMP1:  // FIFO1 有消息等待读出（收到了数据）
        CAN_ReceiveMessage(this->CANInstance, CAN_FIFO1, &lib_rx_msg);
        NotifyMsg(this, &lib_rx_msg);
        break;
    case CAN_INT_FF0:   // FIFO0 满了
        break;
    case CAN_INT_FF1:   // FIFO1 满了
        break;
    case CAN_INT_FOV0:  // FIFO0 溢出了，已经丢失数据
        CAN_ConfigINT(this->CANInstance, CAN_INT_FMP0, ENABLE);  
        break;
    case CAN_INT_FOV1:  // FIFO1 溢出了，已经丢失数据
        CAN_ConfigINT(this->CANInstance, CAN_INT_FMP1, ENABLE);  
        break;
    default: break;
    }
}


// 接口函数实现

void Can_Init(can_t *this, can_baud_t baud)
{
    CAN_InitType CAN_InitStructure;

    CAN_DeInit(this->CANInstance);

    CAN_InitStruct(&CAN_InitStructure);
    CAN_InitStructure.TTCM              = DISABLE;
    CAN_InitStructure.ABOM              = DISABLE;
    CAN_InitStructure.AWKUM             = DISABLE;
    CAN_InitStructure.NART              = DISABLE;
    CAN_InitStructure.RFLM              = DISABLE;
    CAN_InitStructure.TXFP              = ENABLE;
    CAN_InitStructure.OperatingMode     = CAN_Normal_Mode;
    CAN_InitStructure.RSJW              = CAN_RSJW_1tq;
    CAN_InitStructure.TBS1              = CAN_TBS1;
    CAN_InitStructure.TBS2              = CAN_TBS2_3tq;
    CAN_InitStructure.BaudRatePrescaler = F_PCLK1/(CAN_BIT_CYCLE * (int)baud);
    CAN_Init(this->CANInstance, &CAN_InitStructure);

    CAN_ConfigINT(this->CANInstance, CAN_INT_FMP0|CAN_INT_FF0|CAN_INT_FOV0|CAN_INT_FMP1|CAN_INT_FF1|CAN_INT_FOV1, ENABLE);  // 开启中断：FIFO 有数据包待处理、已满、溢出

    this->IsOpen = true;
    Polsys_InitTaskP(&this->NotifyTask, (polsys_task_entry_t)NotifyTaskEntry, (void *)this, POLSYS_WAITING_FOREVER);
}

void Can_SetFilter(can_t *this, can_filter_param_t *filter_param)
{
    CAN_FilterInitType CAN_FilterInitStructure;

    /* CAN filter init */
    CAN_FilterInitStructure.Filter_Num            = filter_param->filter_num;
    CAN_FilterInitStructure.Filter_Mode           = CAN_Filter_IdMaskMode;
    CAN_FilterInitStructure.Filter_Scale          = CAN_Filter_32bitScale;
    if(filter_param->ide == CAN_IDE_STD)
    {
        CAN_FilterInitStructure.Filter_HighId         = CAN_FILTER_STDID(filter_param->id);
        CAN_FilterInitStructure.Filter_LowId          = 0;
        CAN_FilterInitStructure.FilterMask_HighId     = CAN_FILTER_STDID(filter_param->id_mask); // 位为 1 表示该位必须相同
        CAN_FilterInitStructure.FilterMask_LowId      = 0x0000;
    }
    else if(filter_param->ide == CAN_IDE_EXT)
    {
        CAN_FilterInitStructure.Filter_HighId         = CAN_FILTER_EXTID_H(filter_param->id);
        CAN_FilterInitStructure.Filter_LowId          = CAN_FILTER_EXTID_L(filter_param->id);
        CAN_FilterInitStructure.FilterMask_HighId     = CAN_FILTER_EXTID_H(filter_param->id_mask); // 位为 1 表示该位必须相同
        CAN_FilterInitStructure.FilterMask_LowId      = CAN_FILTER_EXTID_L(filter_param->id_mask);
    }
    else
    {
        CAN_FilterInitStructure.Filter_HighId         = 0;
        CAN_FilterInitStructure.Filter_LowId          = 0;
        CAN_FilterInitStructure.FilterMask_HighId     = 0;
        CAN_FilterInitStructure.FilterMask_LowId      = 0;
    }
    CAN_FilterInitStructure.Filter_FIFOAssignment = filter_param->fifo_num;
    CAN_FilterInitStructure.Filter_Act            = ENABLE;
    CAN_InitFilter(this->CANInstance, &CAN_FilterInitStructure);
}

bool Can_AddRxCb(can_t *this, can_rx_cb_t cb, void *user_param)
{
    if(this->RxCbNum < this->RxCbMaxNum)
    {
        this->RxCb[this->RxCbNum] = cb;
        this->RxCbParam[this->RxCbNum] = user_param;
        this->RxCbNum++;
        return true;
    }
    else
    {
        return false;
    }
}

bool Can_Send(can_t *this, can_msg_t *msg)
{
    CanTxMessage LibMsg;
    u8 ret = CAN_TxSTS_NoMailBox;
    int i = 0;

    if(msg->IDE == CAN_IDE_STD)
    {
        LibMsg.StdId = msg->ID;
        LibMsg.IDE = CAN_ID_STD;
    }
    else
    {
        LibMsg.ExtId = msg->ID;
        LibMsg.IDE = CAN_ID_EXT;
    }
    LibMsg.RTR = (u8)msg->RTR;
    LibMsg.DLC = msg->DLC;
    memcpy(LibMsg.Data, msg->Data, 8);
    while(ret == CAN_TxSTS_NoMailBox)
    {
        ret = CAN_TransmitMessage(this->CANInstance, &LibMsg);
        i++;
        if(i == 40 * F_HCLK_MHZ)    // 约2.4ms
            return false;
    }
    return true;
}

////////////////////////////////////// 内部函数实现

/**
 * 通知收到的数据包(CAN接口收到一个数据包事件)，运行在中断中。
 * @param this CAN接口对象
 * @param lrmsg 收到的数据包，库函数格式。
*/
static void NotifyMsg(can_t *this, CanRxMessage *lrmsg)
{
    int i;

    if(lrmsg->IDE == CAN_ID_STD)
    {
        this->NotifyingMsg.ID = lrmsg->StdId;
    }
    else
    {
        this->NotifyingMsg.ID = lrmsg->ExtId;
    }
    this->NotifyingMsg.IDE = lrmsg->IDE;
    this->NotifyingMsg.RTR = lrmsg->RTR;
    this->NotifyingMsg.DLC = lrmsg->DLC;
    for(i=0; i<8; i++)
    {
        this->NotifyingMsg.Data[i] = lrmsg->Data[i];
    }
    
    // 关闭中断，处理完数据之前不再读取接收FIFO
    CAN_ConfigINT(this->CANInstance, CAN_INT_FMP0|CAN_INT_FMP1, DISABLE);  

    // 让 polsys 线程去处理
    Polsys_SetTaskReady(&this->NotifyTask);
}

/**
 * 事件通知任务，每当有事件需要通知时执行一次，运行在 polsys 线程
 * @param this CAN接口对象
*/
static void NotifyTaskEntry(can_t *this)
{
    int i;
    for(i = 0; i< this->RxCbNum; i++)
    {
        bool ret = this->RxCb[i]((can_msg_t *)(&this->NotifyingMsg), this, this->RxCbParam[i]);
        // ！！！！！！！！！！！这里可以优化：通知事件代码，依据事件代码获取数据，参考 LVGL。
        if(ret) break;
    }
    // 开启收到数据中断，继续读取FIFO中的数据（若有）
    CAN_ConfigINT(this->CANInstance, CAN_INT_FMP0|CAN_INT_FMP1, ENABLE);  
}



/////////////////////////////////////// 库函数优化 /////////////////////////////////////////////
// 这里的函数修改自库函数

/* CAN Filter Master Register bits */
#define FMC_FINITM ((uint32_t)0x00000001) /* Filter init mode */

/**
 * 初始化(配置)CAN过滤器，参照 CAN_FilterInitType 的值。
 * 官方库函数有2个一样的函数来分别配置CAN1和CAN2，这里合并。
*/
static void CAN_InitFilter(CAN_Module *CANx, CAN_FilterInitType* CAN_InitFilterStruct)
{
    uint32_t filter_number_bit_pos = 0;
    /* Check the parameters */
    assert_param(IS_CAN_FILTER_NUM(CAN_InitFilterStruct->Filter_Num));
    assert_param(IS_CAN_FILTER_MODE(CAN_InitFilterStruct->Filter_Mode));
    assert_param(IS_CAN_FILTER_SCALE(CAN_InitFilterStruct->Filter_Scale));
    assert_param(IS_CAN_FILTER_FIFO(CAN_InitFilterStruct->Filter_FIFOAssignment));
    assert_param(IS_FUNCTIONAL_STATE(CAN_InitFilterStruct->Filter_Act));

    filter_number_bit_pos = ((uint32_t)1) << CAN_InitFilterStruct->Filter_Num;

    /* Initialisation mode for the filter */
    CANx->FMC |= FMC_FINITM;

    /* Filter Deactivation */
    CANx->FA1 &= ~(uint32_t)filter_number_bit_pos;

    /* Filter Scale */
    if (CAN_InitFilterStruct->Filter_Scale == CAN_Filter_16bitScale)
    {
        /* 16-bit scale for the filter */
        CANx->FS1 &= ~(uint32_t)filter_number_bit_pos;

        /* First 16-bit identifier and First 16-bit mask */
        /* Or First 16-bit identifier and Second 16-bit identifier */
        CANx->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR1 =
            ((0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_LowId) << 16)
            | (0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_LowId);

        /* Second 16-bit identifier and Second 16-bit mask */
        /* Or Third 16-bit identifier and Fourth 16-bit identifier */
        CANx->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR2 =
            ((0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_HighId) << 16)
            | (0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_HighId);
    }

    if (CAN_InitFilterStruct->Filter_Scale == CAN_Filter_32bitScale)
    {
        /* 32-bit scale for the filter */
        CANx->FS1 |= filter_number_bit_pos;
        /* 32-bit identifier or First 32-bit identifier */
        CANx->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR1 =
            ((0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_HighId) << 16)
            | (0x0000FFFF & (uint32_t)CAN_InitFilterStruct->Filter_LowId);
        /* 32-bit mask or Second 32-bit identifier */
        CANx->sFilterRegister[CAN_InitFilterStruct->Filter_Num].FR2 =
            ((0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_HighId) << 16)
            | (0x0000FFFF & (uint32_t)CAN_InitFilterStruct->FilterMask_LowId);
    }

    /* Filter Mode */
    if (CAN_InitFilterStruct->Filter_Mode == CAN_Filter_IdMaskMode)
    {
        /*Id/Mask mode for the filter*/
        CANx->FM1 &= ~(uint32_t)filter_number_bit_pos;
    }
    else /* CAN_InitFilterStruct->Filter_Mode == CAN_Filter_IdListMode */
    {
        /*Identifier list mode for the filter*/
        CANx->FM1 |= (uint32_t)filter_number_bit_pos;
    }

    /* Filter DATFIFO assignment */
    if (CAN_InitFilterStruct->Filter_FIFOAssignment == CAN_Filter_FIFO0)
    {
        /* DATFIFO 0 assignation for the filter */
        CANx->FFA1 &= ~(uint32_t)filter_number_bit_pos;
    }

    if (CAN_InitFilterStruct->Filter_FIFOAssignment == CAN_Filter_FIFO1)
    {
        /* DATFIFO 1 assignation for the filter */
        CANx->FFA1 |= (uint32_t)filter_number_bit_pos;
    }

    /* Filter activation */
    if (CAN_InitFilterStruct->Filter_Act == ENABLE)
    {
        CANx->FA1 |= filter_number_bit_pos;
    }

    /* Leave the initialisation mode for the filter */
    CANx->FMC &= ~FMC_FINITM;
}

/**
 * @brief  Enables or disables the specified CANx interrupts.
 * @param CANx where x can be 1 or 2 to to select the CAN peripheral.
 * @param CAN_INT specifies the CAN interrupt sources to be enabled or disabled.
 *                 This parameter can be 支持使用 | 组合:
 *                 - CAN_INT_TME,
 *                 - CAN_INT_FMP0,
 *                 - CAN_INT_FF0,
 *                 - CAN_INT_FOV0,
 *                 - CAN_INT_FMP1,
 *                 - CAN_INT_FF1,
 *                 - CAN_INT_FOV1,
 *                 - CAN_INT_EWG,
 *                 - CAN_INT_EPV,
 *                 - CAN_INT_LEC,
 *                 - CAN_INT_ERR,
 *                 - CAN_INT_WKU or
 *                 - CAN_INT_SLK.
 * @param Cmd new state of the CAN interrupts.
 *                   This parameter can be: ENABLE or DISABLE.
 */
static void CAN_ConfigINT(CAN_Module* CANx, uint32_t CAN_INT, FunctionalState Cmd)
{
    /* Check the parameters */
    assert_param(IS_CAN_ALL_PERIPH(CANx));
    assert_param(IS_FUNCTIONAL_STATE(Cmd));

    if (Cmd != DISABLE)
    {
        /* Enable the selected CANx interrupt */
        CANx->INTE |= CAN_INT;
    }
    else
    {
        /* Disable the selected CANx interrupt */
        CANx->INTE &= ~CAN_INT;
    }
}
